package com.caishi.lkx.user.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.caishi.lkx.user.mapper.PositionMapper;
import com.caishi.lkx.user.model.PositionModel;
import com.caishi.lkx.user.model.re.UserPositionReModel;
import com.caishi.lkx.user.service.IPositionService;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.IBaseMapper;
import com.zzw.common.exception.BizRuntimeException;
import com.zzw.common.utils.TimeUtil;

import com.caishi.lkx.user.mapper.re.UserPositionReMapper;

import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author by keray
 * date:2021/4/20 3:59 下午
 */
@Service
public class PositionServiceImpl implements IPositionService {

    @Resource
    private PositionMapper positionMapper;

    @Resource
    private UserPositionReMapper userPositionReMapper;

    @Override
    public IBaseMapper<PositionModel, Long> getMapper() {
        return positionMapper;
    }

    @Override
    public List<PositionModel> userNextLevelPosition(String userId) {
        return userPositionReMapper.userNextPositions(userId, LocalDateTime.now());
    }

    @Override
    public PositionModel insert(PositionModel entity) {
        if (codeHave(entity.getCode())) {
            throw new BizRuntimeException("code已经存在");
        }
        Assert.notEmpty(entity.getCode(), "code必填");
        Assert.notEmpty(entity.getName(), "名称必填");
        return IPositionService.super.insert(entity);
    }

    @Override
    public List<PositionModel> userHavePosition(String userId) {
        List<Long> positionIds = userPositionReMapper.selectList(
                Wrappers.<UserPositionReModel>lambdaQuery()
                        .select(UserPositionReModel::getPositionId)
                        .eq(UserPositionReModel::getUserId, userId)
                        .gt(UserPositionReModel::getExpireTime, LocalDateTime.now())
        ).stream().map(UserPositionReModel::getPositionId).collect(Collectors.toList());
        if (CollUtil.isEmpty(positionIds)) {
            return Collections.emptyList();
        }
        return positionMapper.selectList(
                Wrappers.<PositionModel>lambdaQuery()
                        .in(PositionModel::getId, positionIds)
        );
    }

    @Override
    public void userSettingPosition(String userId, List<UserPositionReModel> positions) {
        List<Long> oldIds = userPositionReMapper.selectList(Wrappers.<UserPositionReModel>lambdaQuery()
                .select(UserPositionReModel::getPositionId)
                .eq(UserPositionReModel::getUserId, userId)
        ).stream().map(UserPositionReModel::getPositionId).collect(Collectors.toList());
        List<Long> newIds = positions.stream().map(UserPositionReModel::getPositionId).collect(Collectors.toList());
        List<Long> delIds = oldIds.stream().filter(id -> !newIds.contains(id)).collect(Collectors.toList());
        List<Long> addIds = newIds.stream().filter(id -> !oldIds.contains(id)).collect(Collectors.toList());
        List<Long> upIds = newIds.stream().filter(oldIds::contains).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(delIds)) {
            removeUserPosition(userId, delIds);
        }
        if (CollectionUtil.isNotEmpty(addIds)) {
            addUserPosition(userId, positions.stream().filter(v -> addIds.contains(v.getPositionId())).collect(Collectors.toList()));
        }
        if (CollectionUtil.isNotEmpty(upIds)) {
            upUserPosition(userId, positions.stream().filter(v -> upIds.contains(v.getPositionId())).collect(Collectors.toList()));
        }
    }

    @Override
    public void userSettingPositionByIds(String userId, List<Long> positionIds) {
        owner(IPositionService.class).userSettingPosition(userId,
                positionIds
                        .stream().map(id -> UserPositionReModel.builder()
                        .positionId(id)
                        .userId(userId)
                        .expireTime(TimeUtil.MAX)
                        .build())
                        .collect(Collectors.toList())
        );
    }

    private void addUserPosition(String userId, List<UserPositionReModel> data) {
        data.forEach(v -> v.setUserId(userId));
        userPositionReMapper.insertBatch(data);
    }

    private void upUserPosition(String userId, List<UserPositionReModel> data) {
        data.stream().forEach(v -> {
            if (v.getExpireTime() != null) {
                userPositionReMapper.update(null, Wrappers.<UserPositionReModel>lambdaUpdate()
                        .set(UserPositionReModel::getExpireTime, v.getExpireTime())
                        .eq(UserPositionReModel::getUserId, userId)
                        .eq(UserPositionReModel::getPositionId, v.getPositionId())
                        .ne(UserPositionReModel::getExpireTime, v.getExpireTime())
                );
            }
        });
    }

    private void removeUserPosition(String userId, List<Long> delIds) {
        userPositionReMapper.delete(Wrappers.<UserPositionReModel>lambdaUpdate()
                .eq(UserPositionReModel::getUserId, userId)
                .in(UserPositionReModel::getPositionId, delIds)
        );
    }

    @Override
    public boolean codeHave(String code) {
        return selectCount(Wrappers.<PositionModel>lambdaQuery().eq(PositionModel::getCode, code)) > 0;
    }

    @Override
    public PositionModel builder() {
        return new PositionModel();
    }
}
